home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 42 / Amiga Format AFCD42 (Issue 126, Aug 1999).iso / -serious- / comms / other / slrn / slrn_src / src / mime.c < prev    next >
C/C++ Source or Header  |  1999-05-14  |  24KB  |  1,009 lines

  1. /* Copyright (c) 1998 John E. Davis (davis@space.mit.edu)
  2.  *
  3.  * This file is part of slrn.
  4.  *
  5.  * Slrn is free software; you can redistribute it and/or modify it
  6.  * under the terms of the GNU General Public License as published by the
  7.  * Free Software Foundation; either version 2, or (at your option) any
  8.  * later version.
  9.  * 
  10.  * Slrn is distributed in the hope that it will be useful, but WITHOUT
  11.  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12.  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  13.  * for more details.
  14.  * 
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with Slrn; see the file COPYING.  If not, write to the Free
  17.  * Software Foundation, 59 Temple Place - Suite 330, 
  18.  * Boston, MA  02111-1307, USA.
  19.  */
  20.  
  21. /* MIME handling routines.
  22.  *
  23.  * Author: Michael Elkins <elkins@aero.org>
  24.  * Modified by John E. Davis <davis@space.mit.edu>
  25.  * 
  26.  * Change Log:
  27.  * Aug 20, 1997 patch from "Byrial Jensen" <byrial@post3.tele.dk>
  28.  *   added.  Apparantly RFC2047 requires the whitespace separating
  29.  *   multiple encoded words in headers to be ignored.
  30.  *   Status: unchecked
  31.  */
  32.  
  33. #include "config.h"
  34. #include "slrnfeat.h"
  35.  
  36. #include <stdio.h>
  37. #include <string.h>
  38.  
  39.  
  40. #ifdef HAVE_STDLIB_H
  41. # include <stdlib.h>
  42. #endif
  43.  
  44. #ifdef HAVE_UNISTD_H
  45. # include <unistd.h>
  46. #endif
  47.  
  48. #include <ctype.h>
  49.  
  50. #if defined(__os2__) || defined(__NT__)
  51. # include <process.h>
  52. #endif
  53.  
  54. #include <slang.h>
  55. #include "jdmacros.h"
  56.  
  57. #include "server.h"
  58. #include "slrn.h"
  59. #include "misc.h"
  60. #include "slrn.h"
  61. #include "group.h"
  62. #include "art.h"
  63. #include "util.h"
  64.  
  65. #if SLRN_HAS_MIME
  66. /* rest of file in this ifdef */
  67.  
  68. #include "mime.h"
  69.  
  70. int Slrn_Use_Mime = 1;
  71. int Slrn_Use_Meta_Mail = 1;
  72. char *Slrn_MetaMail_Cmd;
  73.  
  74. int Slrn_Mime_Was_Parsed;
  75. int Slrn_Mime_Was_Modified;
  76. int Slrn_Mime_Needs_Metamail;
  77.  
  78. char *Slrn_Mime_Display_Charset;
  79.  
  80. /* These are all supersets of US-ASCII.  Only the first N characters are 
  81.  * matched, where N is the length of the table entry.
  82.  */
  83. static char *Compatable_Charsets[] =
  84. {
  85.    "US-ASCII",                   /* This MUST be zeroth element */
  86.    "ISO-8859-",
  87.    "iso-latin1",               /* knews adds his one */
  88.    "KOI8-R",
  89.    NULL
  90. };
  91.  
  92. static char *Char_Set;
  93. static int Content_Type;
  94. #define CONTENT_TYPE_TEXT        0x01
  95. #define CONTENT_TYPE_MESSAGE        0x02
  96. #define CONTENT_TYPE_MULTIPART        0x03
  97. #define CONTENT_TYPE_UNSUPPORTED    0x10
  98.  
  99. static int Content_Subtype;
  100. #define CONTENT_SUBTYPE_PLAIN        0x01
  101. #define CONTENT_SUBTYPE_UNKNOWN        0x02
  102. #define CONTENT_SUBTYPE_UNSUPPORTED    0x10
  103.  
  104. static int Encoding_Method;
  105. #define ENCODED_7BIT            1
  106. #define ENCODED_8BIT            2
  107. #define ENCODED_QUOTED            3
  108. #define ENCODED_BASE64            4
  109. #define ENCODED_BINARY            5
  110. #define ENCODED_UNSUPPORTED        6
  111.  
  112. #ifndef isalnum
  113. #define isalnum(x) \
  114.   ((((x) <= 'Z') && ((x) >= 'A')) \
  115.    || (((x) <= 'z') && ((x) >= 'a')) \
  116.    || (((x) <= '9') && ((x) >= '0')))
  117. #endif
  118.  
  119. static Slrn_Article_Line_Type *find_header_line (char *header)
  120. {
  121.    Slrn_Article_Line_Type *line = Slrn_Article_Lines;
  122.    unsigned char ch = (unsigned char) UPPER_CASE(*header);
  123.    unsigned int len = strlen (header);
  124.    
  125.    while ((line != NULL) && (line->flags & HEADER_LINE))
  126.      {
  127.     unsigned char ch1 = (unsigned char) *line->buf;
  128.     if ((ch == UPPER_CASE(ch1))
  129.         && (0 == slrn_case_strncmp ((unsigned char *)header,
  130.                     (unsigned char *)line->buf,
  131.                     len)))
  132.       return line;
  133.     line = line->next;
  134.      }
  135.    return NULL;
  136. }
  137.  
  138.  
  139. static char *find_compatable_charset (char *cs, unsigned int len)
  140. {
  141.    char **compat_charset;
  142.    
  143.    compat_charset = Compatable_Charsets;
  144.    while (*compat_charset != NULL)
  145.      {
  146.     unsigned int len1;
  147.     
  148.     len1 = strlen (*compat_charset);
  149.     if (len1 <= len) 
  150.       {
  151.          if (0 == slrn_case_strncmp ((unsigned char *) cs,
  152.                      (unsigned char *) *compat_charset,
  153.                      len1))
  154.            return *compat_charset;
  155.       }
  156.     compat_charset++;
  157.      }
  158.    return NULL;
  159. }
  160.  
  161. static int parse_content_type_line (void)
  162. {
  163.    Slrn_Article_Line_Type *line;
  164.    char *b;
  165.    
  166.    /* Use default: text/plain; charset=us-ascii */
  167.    Content_Type = CONTENT_TYPE_TEXT;
  168.    Content_Subtype = CONTENT_SUBTYPE_PLAIN;
  169.    Char_Set = Compatable_Charsets[0];
  170.    
  171.    if (NULL == (line = find_header_line ("Content-Type:")))
  172.      return 0;
  173.    
  174.    b = slrn_skip_whitespace (line->buf + 13);
  175.    
  176.    if (0 == slrn_case_strncmp ((unsigned char *)b,
  177.                    (unsigned char *) "text/",
  178.                    5))
  179.      {
  180.     b += 5;
  181.     if (0 != slrn_case_strncmp ((unsigned char *)b,
  182.                     (unsigned char *) "plain",
  183.                     5))
  184.       {
  185.          Content_Subtype = CONTENT_SUBTYPE_UNSUPPORTED;
  186.          return -1;
  187.       }
  188.     b += 5;
  189.      }
  190.    else if (0 == slrn_case_strncmp ((unsigned char *)b,
  191.                     (unsigned char *) "message/",
  192.                     5))
  193.      {
  194.     Content_Type = CONTENT_TYPE_MESSAGE;
  195.     Content_Subtype = CONTENT_SUBTYPE_UNKNOWN;
  196.     b += 8;
  197.      }
  198.    else if (0 == slrn_case_strncmp ((unsigned char *)b,
  199.                     (unsigned char *) "multipart/",
  200.                     5))
  201.      {
  202.     Content_Type = CONTENT_TYPE_MULTIPART;
  203.     Content_Subtype = CONTENT_SUBTYPE_UNKNOWN;
  204.     b += 10;
  205.      }
  206.    else
  207.      {
  208.     Content_Type = CONTENT_TYPE_UNSUPPORTED;
  209.     return -1;
  210.      }
  211.    
  212.    do
  213.      {
  214.     while (NULL != (b = slrn_strchr (b, ';')))
  215.       {
  216.          char *charset;
  217.          unsigned int len;
  218.          
  219.          b = slrn_skip_whitespace (b + 1);
  220.          
  221.          if (0 != slrn_case_strncmp ((unsigned char *)b,
  222.                      (unsigned char *)"charset",
  223.                      7))
  224.            continue;
  225.          
  226.          b = slrn_skip_whitespace (b + 7);
  227.          while (*b == 0)
  228.            {
  229.           line = line->next;
  230.           if ((line == NULL)
  231.               || ((line->flags & HEADER_LINE) == 0)
  232.               || ((*(b = line->buf) != ' ') && (*b == '\t')))
  233.             return -1;
  234.           b = slrn_skip_whitespace (b);
  235.            }
  236.          
  237.          if (*b != '=') continue;
  238.          b++;
  239.          if (*b == '"') b++;
  240.          charset = b;
  241.          while (*b && (*b != ';')
  242.             && (*b != ' ') && (*b != '\t') && (*b != '\n')
  243.             && (*b != '"'))
  244.            b++;
  245.          len = b - charset;
  246.          
  247.          Char_Set = find_compatable_charset (charset, len);
  248.          if (Char_Set == NULL) return -1;
  249.          return 0;
  250.       }
  251.     line = line->next;
  252.      }
  253.    while ((line != NULL)
  254.       && (line->flags & HEADER_LINE)
  255.       && ((*(b = line->buf) == ' ') || (*b == '\t')));
  256.    
  257.    return 0;
  258. }
  259.  
  260. static int parse_content_transfer_encoding_line (void)
  261. {
  262.    Slrn_Article_Line_Type *line;
  263.    unsigned char *buf;
  264.    
  265.    Encoding_Method = ENCODED_7BIT;
  266.    line = find_header_line ("Content-Transfer-Encoding:");
  267.    if (line == NULL) return 0;
  268.    
  269.    buf = (unsigned char *) slrn_skip_whitespace (line->buf + 26);
  270.    if (*buf == '"') buf++;
  271.    
  272.    if (0 == slrn_case_strncmp (buf, (unsigned char *) "7bit", 4))
  273.      Encoding_Method = ENCODED_7BIT;
  274.    else if (0 == slrn_case_strncmp (buf, (unsigned char *) "8bit", 4))
  275.      Encoding_Method = ENCODED_8BIT;
  276.    else if (0 == slrn_case_strncmp (buf, (unsigned char *) "base64", 6))
  277.      Encoding_Method = ENCODED_BASE64;
  278.    else if (0 == slrn_case_strncmp (buf, (unsigned char *) "quoted-printable", 16))
  279.      Encoding_Method = ENCODED_QUOTED;
  280.    else if (0 == slrn_case_strncmp (buf, (unsigned char *) "binary", 6))
  281.      Encoding_Method = ENCODED_BINARY;
  282.    else
  283.      {
  284.     Encoding_Method = ENCODED_UNSUPPORTED;
  285.     return -1;
  286.      }
  287.    return 0;
  288. }
  289.  
  290. static int Index_Hex[128] =
  291. {
  292.    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
  293.      -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
  294.      -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
  295.      0, 1, 2, 3,  4, 5, 6, 7,  8, 9,-1,-1, -1,-1,-1,-1,
  296.      -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1,
  297.      -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
  298.      -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1,
  299.      -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1
  300. };
  301. #define HEX(c) (Index_Hex[(unsigned char)(c) & 0x7F])
  302.  
  303. static char *decode_quoted_printable (char *dest,
  304.                       char *src, char *srcmax,
  305.                       int treat_underscore_as_space)
  306. {
  307.    char *allowed_in_qp = "0123456789ABCDEFabcdef";
  308.    char ch;
  309.    while (src < srcmax)
  310.      {
  311.     ch = *src++;
  312.     if ((ch == '=') && (src + 1 < srcmax)
  313.         && (NULL != slrn_strchr (allowed_in_qp, src[0]))
  314.         && (NULL != slrn_strchr (allowed_in_qp, src[1])))
  315.       {
  316.          *dest++ = (16 * HEX(src[0])) + HEX(src[1]);
  317.          src += 2;
  318.       }
  319.     else if ((ch == '_') && treat_underscore_as_spa